//+------------------------------------------------------------------+
//|                                                       Dialog.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.h"    // 窗口容器基类（提供控件容器核心能力）
#include "WndClient.h"       // 客户区控件类（用于承载自定义子控件）
#include "Panel.h"           // 面板控件类（用于背景、边框等装饰性元素）
#include "Edit.h"            // 编辑框控件类（用于标题、输入框等文本显示/输入）
#include "BmpButton.h"       // 位图按钮类（带图片的交互按钮）
#include <Charts/Chart.h>    // 图表操作类（用于MQL5图表属性控制）

//+------------------------------------------------------------------+
//| 资源声明：对话框所需的位图资源                                   |
//+------------------------------------------------------------------+
#resource "res\\Close.bmp"    // 关闭按钮位图（静态显示，无状态切换）
#resource "res\\Restore.bmp"  // 恢复（最大化）按钮位图（切换到正常窗口状态）
#resource "res\\Turn.bmp"     // 最小化按钮位图（切换到紧凑窗口状态）

//+------------------------------------------------------------------+
//| CDialog 类：MQL5 基础对话框基类                                  |
//| 核心能力：提供通用对话框的基础结构（标题栏、关闭按钮、客户区等）， |
//|           支持拖拽、尺寸状态保存，可作为自定义对话框/面板的父类    |
//+------------------------------------------------------------------+
class CDialog : public CWndContainer
  {
private:
   // 子控件：构成基础对话框的核心元素（私有，仅内部管理）
   CPanel            m_white_border;        // 白色边框面板（非面板模式下显示，优化视觉层次）
   CPanel            m_background;          // 背景面板（填充对话框背景色，区分于图表背景）
   CEdit             m_caption;             // 标题栏编辑框（显示对话框标题，只读）
   CBmpButton        m_button_close;        // 关闭按钮（点击后隐藏对话框）
   CWndClient        m_client_area;         // 客户区（用于添加自定义业务控件，如按钮、输入框等）

protected:
   // 对话框状态与尺寸参数（保护，允许子类访问和修改）
   bool              m_panel_flag;          // 面板模式标志：true=作为独立子窗口面板，false=作为普通悬浮对话框
   bool              m_minimized;           // 最小化状态标志：true=当前为最小化，false=正常尺寸
   CRect             m_min_rect;            // 最小化状态的坐标与尺寸（存储紧凑模式下的位置和大小）
   CRect             m_norm_rect;           // 正常状态的坐标与尺寸（存储完整模式下的位置和大小）

public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化基础对话框的默认状态
    * @details 初始化面板模式为普通对话框（false）、最小化状态为未最小化（false），
    *          尺寸参数（m_min_rect/m_norm_rect）初始化为空
    */
                     CDialog(void);

   /**
    * @brief 析构函数：清理对话框资源
    * @details 依赖父类 CWndContainer 的析构逻辑，自动释放所有子控件（边框、背景、按钮等）
    *          及动态分配的内存
    */
                    ~CDialog(void);

   //----------------------------------------------------------------
   // 控件创建：初始化对话框并添加到图表
   //----------------------------------------------------------------
   /**
    * @brief 在指定图表位置创建基础对话框
    * @param chart [in] 目标图表ID（0 表示当前活跃图表，可通过 ChartID() 获取）
    * @param name [in] 对话框唯一标识名（图表内不可重复，用于区分多个控件）
    * @param subwin [in] 绑定的子窗口编号（0 = 主图表窗口，≥1 = 指标子窗口）
    * @param x1 [in] 对话框左上角X坐标（像素，相对于图表窗口左上角）
    * @param y1 [in] 对话框左上角Y坐标（像素）
    * @param x2 [in] 对话框右下角X坐标（像素）
    * @param y2 [in] 对话框右下角Y坐标（像素）
    * @return bool - 创建结果：true=成功（父类初始化+子控件创建完成），false=失败
    * @note 1. 非面板模式下会创建白色边框，面板模式仅创建背景和客户区；
    *       2. 自动初始化正常状态尺寸（m_norm_rect）为创建时的尺寸
    */
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);

   //----------------------------------------------------------------
   // 事件处理：响应图表与子控件事件
   //----------------------------------------------------------------
   /**
    * @brief 统一处理图表事件（子控件事件通过事件映射分发）
    * @param id [in] 事件ID（如 ON_CLICK、ON_DRAG、CHARTEVENT_MOUSE_MOVE 等）
    * @param lparam [in] 长整数参数（事件相关数据，如子控件ID、鼠标X坐标等）
    * @param dparam [in] 双精度参数（事件相关数据，如鼠标Y坐标等）
    * @param sparam [in] 字符串参数（事件相关数据，如控件名称等）
    * @return bool - 处理结果：true=事件已处理，false=未处理（交由父类或系统处理）
    */
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //----------------------------------------------------------------
   // 标题栏配置：设置/获取对话框标题
   //----------------------------------------------------------------
   /**
    * @brief 获取当前对话框的标题文本
    * @return string - 标题文本（从 m_caption 编辑框中读取）
    */
   string            Caption(void) const;

   /**
    * @brief 设置对话框的标题文本
    * @param text [in] 目标标题文本（将显示在对话框顶部标题栏）
    * @return bool - 设置结果：true=成功（文本框更新完成），false=失败
    */
   bool              Caption(const string text);

   //----------------------------------------------------------------
   // 客户区管理：向客户区添加自定义子控件
   //----------------------------------------------------------------
   /**
    * @brief 向客户区添加子控件（通过指针）
    * @param control [in] 子控件指针（需提前创建，如 CButton、CEdit 等）
    * @return bool - 添加结果：true=成功（控件添加到 m_client_area），false=失败
    * @note 适用于动态创建的控件（需自行管理内存释放）
    */
   bool              Add(CWnd *control);

   /**
    * @brief 向客户区添加子控件（通过引用）
    * @param control [in] 子控件引用（通常为栈上创建的局部控件）
    * @return bool - 添加结果：true=成功，false=失败
    * @note 适用于静态创建的控件（无需手动释放内存）
    */
   bool              Add(CWnd &control);

   //----------------------------------------------------------------
   // 状态序列化：保存/加载对话框状态到文件
   //----------------------------------------------------------------
   /**
    * @brief 将对话框状态（尺寸、位置、最小化状态）保存到文件
    * @param file_handle [in] 文件句柄（需提前以 FILE_WRITE 模式打开，如 FileOpen 返回的有效句柄）
    * @return bool - 保存结果：true=成功（状态写入文件），false=失败（文件无效或写入错误）
    */
   virtual bool      Save(const int file_handle);

   /**
    * @brief 从文件加载对话框状态（恢复尺寸、位置、最小化状态）
    * @param file_handle [in] 文件句柄（需提前以 FILE_READ 模式打开）
    * @return bool - 加载结果：true=成功（状态从文件读取并应用），false=失败
    */
   virtual bool      Load(const int file_handle);

protected:
   //----------------------------------------------------------------
   // 内部子控件创建：初始化对话框的核心组成部分（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 创建白色边框面板（仅非面板模式生效）
    * @return bool - 创建结果：true=成功（边框面板添加到对话框），false=失败
    */
   virtual bool      CreateWhiteBorder(void);

   /**
    * @brief 创建背景面板（填充对话框背景）
    * @return bool - 创建结果：true=成功（背景色、边框色配置完成），false=失败
    */
   virtual bool      CreateBackground(void);

   /**
    * @brief 创建标题栏编辑框（配置为只读，显示标题）
    * @return bool - 创建结果：true=成功（文本颜色、背景色、对齐方式配置完成），false=失败
    */
   virtual bool      CreateCaption(void);

   /**
    * @brief 创建关闭按钮（绑定关闭位图，设置点击事件）
    * @return bool - 创建结果：true=成功（按钮位置、位图配置完成），false=失败
    */
   virtual bool      CreateButtonClose(void);

   /**
    * @brief 创建客户区（用于承载自定义子控件）
    * @return bool - 创建结果：true=成功（客户区位置、尺寸、背景色配置完成），false=失败
    */
   virtual bool      CreateClientArea(void);

   //----------------------------------------------------------------
   // 子控件事件回调：处理子控件触发的事件（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 标题栏点击事件回调
    * @details 默认空实现，子类可重写以添加自定义逻辑（如双击最大化/最小化）
    */
   virtual void      OnClickCaption(void);

   /**
    * @brief 关闭按钮点击事件回调
    * @details 默认逻辑：设置对话框为不可见（Visible(false)）
    */
   virtual void      OnClickButtonClose(void);

   //----------------------------------------------------------------
   // 标题栏属性访问：配置标题栏的对齐方式与内边距（保护，仅子类可调用）
   //----------------------------------------------------------------
   /**
    * @brief 设置标题栏文本的对齐方式与内边距
    * @param flags [in] 对齐标志（如 TA_CENTER | TA_VCENTER 表示居中对齐）
    * @param left [in] 左内边距（像素，文本与标题栏左侧的距离）
    * @param top [in] 上内边距（像素，文本与标题栏顶部的距离）
    * @param right [in] 右内边距（像素，文本与标题栏右侧的距离）
    * @param bottom [in] 下内边距（像素，文本与标题栏底部的距离）
    */
   void              CaptionAlignment(const int flags,const int left,const int top,const int right,const int bottom);

   //----------------------------------------------------------------
   // 客户区属性访问：获取/设置客户区的可见性与尺寸（保护，仅子类可调用）
   //----------------------------------------------------------------
   /**
    * @brief 设置客户区的可见性
    * @param visible [in] 可见状态：true=显示客户区及内部控件，false=隐藏
    * @return bool - 设置结果：true=成功，false=失败
    */
   bool              ClientAreaVisible(const bool visible);

   /**
    * @brief 获取客户区左上角X坐标（像素，相对于对话框左上角）
    * @return int - 客户区左边界坐标
    */
   int               ClientAreaLeft(void) const;

   /**
    * @brief 获取客户区左上角Y坐标（像素，相对于对话框左上角）
    * @return int - 客户区上边界坐标
    */
   int               ClientAreaTop(void) const;

   /**
    * @brief 获取客户区右下角X坐标（像素，相对于对话框左上角）
    * @return int - 客户区右边界坐标
    */
   int               ClientAreaRight(void) const;

   /**
    * @brief 获取客户区右下角Y坐标（像素，相对于对话框左上角）
    * @return int - 客户区下边界坐标
    */
   int               ClientAreaBottom(void) const;

   /**
    * @brief 获取客户区宽度（像素）
    * @return int - 客户区宽度
    */
   int               ClientAreaWidth(void) const;

   /**
    * @brief 获取客户区高度（像素）
    * @return int - 客户区高度
    */
   int               ClientAreaHeight(void) const;

   //----------------------------------------------------------------
   // 拖拽事件处理：处理对话框的拖拽逻辑（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 拖拽开始事件回调（标题栏按下鼠标时触发）
    * @return bool - 处理结果：true=成功（创建拖拽辅助对象，初始化拖拽参数），false=失败
    */
   virtual bool      OnDialogDragStart(void);

   /**
    * @brief 拖拽过程事件回调（鼠标移动时触发）
    * @return bool - 处理结果：true=成功（根据鼠标位置更新对话框位置），false=失败
    */
   virtual bool      OnDialogDragProcess(void);

   /**
    * @brief 拖拽结束事件回调（鼠标松开时触发）
    * @return bool - 处理结果：true=成功（销毁拖拽辅助对象，保存当前位置），false=失败
    */
   virtual bool      OnDialogDragEnd(void);
  };

//+------------------------------------------------------------------+
//| CDialog 事件映射：关联子控件事件到对应的处理函数                 |
//| 作用：MQL5 控件框架通过事件映射自动分发子控件事件，无需手动注册  |
//+------------------------------------------------------------------+
// EVENT_MAP_BEGIN(CDialog)
//    ON_EVENT(ON_CLICK, m_button_close, OnClickButtonClose)  // 关闭按钮点击事件 → 调用 OnClickButtonClose
//    ON_EVENT(ON_CLICK, m_caption,      OnClickCaption)     // 标题栏点击事件 → 调用 OnClickCaption
//    ON_EVENT(ON_DRAG_START, m_caption, OnDialogDragStart)  // 标题栏拖拽开始事件 → 调用 OnDialogDragStart
//    ON_EVENT_PTR(ON_DRAG_PROCESS, m_drag_object, OnDialogDragProcess)  // 拖拽过程事件 → 调用 OnDialogDragProcess
//    ON_EVENT_PTR(ON_DRAG_END, m_drag_object, OnDialogDragEnd)          // 拖拽结束事件 → 调用 OnDialogDragEnd
// EVENT_MAP_END(CWndContainer)

//+------------------------------------------------------------------+
//| CAppDialog 类：MQL5 应用程序主对话框类                           |
//| 核心能力：基于 CDialog 扩展，支持 EA/指标的主交互窗口，提供       |
//|           最小化/最大化、多实例隔离、状态持久化（配置文件）等功能 |
//| 适用场景：EA 的控制面板、指标的参数配置窗口、跨图表的全局交互面板 |
//+------------------------------------------------------------------+
class CAppDialog : public CDialog
  {
private:
   // 扩展子控件：在基础对话框上新增的功能元素（私有，仅内部管理）
   CBmpButton        m_button_minmax;       // 最小化/最大化按钮（切换窗口尺寸模式）

   // 应用程序核心信息（私有，确保多实例隔离）
   string            m_program_name;        // 程序名称（EA/指标的名称，用于标题栏和配置文件）
   string            m_instance_id;         // 实例唯一ID（区分同一程序的多个图表实例，避免冲突）
   ENUM_PROGRAM_TYPE m_program_type;        // 程序类型（PROGRAM_EXPERT=EA，PROGRAM_INDICATOR=指标）
   string            m_indicator_name;      // 指标短名称（仅指标模式生效，用于绑定子窗口）
   int               m_deinit_reason;       // 程序退出原因（如 REASON_PROGRAM=主动退出，REASON_CHARTCLOSE=图表关闭）

   // 鼠标与焦点管理（私有，优化交互体验）
   int               m_subwin_Yoff;         // 子窗口Y轴偏移量（校准鼠标坐标到对话框局部坐标系）
   CWnd*             m_focused_wnd;         // 当前获得鼠标焦点的子控件指针（用于键盘输入等交互）
   CWnd*             m_top_wnd;             // 鼠标事件优先处理的子控件指针（如弹窗覆盖时优先响应弹窗）

protected:
   CChart            m_chart;               // 图表操作对象（用于控制图表子窗口尺寸、事件配置等）

public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化应用主对话框的默认状态
    * @details 初始化程序类型为无效值（WRONG_VALUE）、退出原因为无效值，
    *          焦点与鼠标相关指针初始化为空，确保多实例隔离
    */
                     CAppDialog(void);

   /**
    * @brief 析构函数：清理应用主对话框资源
    * @details 释放图表对象（m_chart）、子控件及动态分配的内存，
    *          确保程序退出时无资源泄漏
    */
                    ~CAppDialog(void);

   //----------------------------------------------------------------
   // 应用对话框创建与销毁：初始化程序环境并清理资源
   //----------------------------------------------------------------
   /**
    * @brief 创建应用主对话框（根据程序类型适配 EA/指标模式）
    * @param chart [in] 目标图表ID
    * @param name [in] 程序名称（作为对话框标题和配置文件前缀）
    * @param subwin [in] 绑定的子窗口编号
    * @param x1 [in] 对话框左上角X坐标
    * @param y1 [in] 对话框左上角Y坐标
    * @param x2 [in] 对话框右下角X坐标
    * @param y2 [in] 对话框右下角Y坐标
    * @return bool - 创建结果：true=成功（适配程序类型+子控件初始化完成），false=失败
    * @note 1. EA 模式：绑定主窗口（subwin=0），支持自由拖拽，最小化为紧凑条；
    *       2. 指标模式：绑定指标子窗口（subwin≥1），自适应子窗口宽度，最小化后仅显示标题栏；
    *       3. 自动生成实例唯一ID（m_instance_id），避免多实例冲突
    */
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);

   /**
    * @brief 销毁应用主对话框（释放资源并退出程序）
    * @param reason [in] 销毁原因（默认 REASON_PROGRAM=主动退出）
    * @note 1. 保存当前状态到配置文件（通过 IniFileSave()）；
    *       2. EA 模式调用 ExpertRemove() 移除EA，指标模式删除绑定的子窗口；
    *       3. 发送 ON_APP_CLOSE 事件，通知其他实例处理子窗口调整
    */
   virtual void      Destroy(const int reason=REASON_PROGRAM);

   //----------------------------------------------------------------
   // 事件处理：扩展基础对话框的事件响应（支持应用级事件）
   //----------------------------------------------------------------
   /**
    * @brief 处理应用级事件（覆盖父类 CDialog::OnEvent）
    * @param id [in] 事件ID
    * @param lparam [in] 长整数参数
    * @param dparam [in] 双精度参数
    * @param sparam [in] 字符串参数
    * @return bool - 处理结果：true=事件已处理（如外部程序关闭、子窗口变化等），false=未处理
    */
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //----------------------------------------------------------------
   // 程序运行：初始化并启动应用对话框
   //----------------------------------------------------------------
   /**
    * @brief 启动应用对话框（完成控件ID分配与图表刷新）
    * @return bool - 启动结果：true=成功（控件ID分配有效），false=失败（ID超出上限 CONTROLS_MAXIMUM_ID）
    * @note 需在 Create() 之后调用，确保对话框正常显示并响应事件
    */
   bool              Run(void);

   //----------------------------------------------------------------
   // 图表事件分发：处理图表原生事件（优化交互体验）
   //----------------------------------------------------------------
   /**
    * @brief 分发图表原生事件到对应的子控件（校准鼠标坐标，处理焦点与优先级）
    * @param id [in] 图表事件ID（如 CHARTEVENT_MOUSE_MOVE、CHARTEVENT_OBJECT_CLICK 等）
    * @param lparam [in] 事件长整数参数（如鼠标X坐标）
    * @param dparam [in] 事件双精度参数（如鼠标Y坐标）
    * @param sparam [in] 事件字符串参数（如鼠标按键状态）
    * @note 1. 校准鼠标Y坐标（减去子窗口偏移 m_subwin_Yoff）；
    *       2. 优先处理 m_top_wnd（如弹窗）的事件，再处理其他控件；
    *       3. 处理焦点切换（ON_MOUSE_FOCUS_SET）和控件置顶（ON_BRING_TO_TOP）事件
    */
   void              ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //----------------------------------------------------------------
   // 状态配置：设置对话框初始最小化状态
   //----------------------------------------------------------------
   /**
    * @brief 设置对话框是否初始为最小化状态
    * @param flag [in] 最小化状态：true=创建后直接最小化，false=创建后为正常尺寸
    * @note 需在 Create() 之前调用，否则需手动调用 Minimize()/Maximize() 切换状态
    */
   void              Minimized(const bool flag);

   //----------------------------------------------------------------
   // 配置文件操作：保存/加载程序状态到本地文件
   //----------------------------------------------------------------
   /**
    * @brief 将程序状态（尺寸、位置、最小化状态、实例ID）保存到配置文件
    * @note 配置文件路径由 IniFileName() + IniFileExt() 生成（如 "MyEA_EURUSD_Init.dat"）
    */
   void              IniFileSave(void);

   /**
    * @brief 从配置文件加载程序状态（恢复上次退出时的尺寸、位置等）
    * @note 若配置文件不存在，使用默认状态（创建时的尺寸与位置）
    */
   void              IniFileLoad(void);

   /**
    * @brief 获取配置文件名称（不含扩展名）
    * @return string - 配置文件名称（格式：[指标短名称/程序名]_[货币对]_Ini）
    * @note 确保不同程序、不同图表的配置文件不冲突
    */
   virtual string    IniFileName(void) const;

   /**
    * @brief 获取配置文件扩展名（默认 .dat）
    * @return string - 配置文件扩展名（带点，如 ".dat"）
    * @note 子类可重写以修改扩展名（如 ".ini"）
    */
   virtual string    IniFileExt(void) const;

   //----------------------------------------------------------------
   // 状态序列化：扩展基础对话框的文件读写（添加应用级信息）
   //----------------------------------------------------------------
   /**
    * @brief 加载程序状态（覆盖父类 CDialog::Load）
    * @param file_handle [in] 文件句柄
    * @return bool - 加载结果：true=成功（恢复尺寸、位置、最小化状态，并清理旧实例残留对象），false=失败
    */
   virtual bool      Load(const int file_handle);

   /**
    * @brief 保存程序状态（覆盖父类 CDialog::Save）
    * @param file_handle [in] 文件句柄
    * @return bool - 保存结果：true=成功（添加退出原因、实例ID等应用级信息），false=失败
    */
   virtual bool      Save(const int file_handle);

private:
   //----------------------------------------------------------------
   // 内部创建逻辑：拆分通用初始化与 EA/指标专属初始化（私有，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 通用初始化（图表绑定、程序类型识别、实例ID生成）
    * @param chart [in] 目标图表ID
    * @param name [in] 程序名称
    * @param subwin [in] 绑定的子窗口编号
    * @return bool - 初始化结果：true=成功（图表事件配置完成），false=失败
    */
   bool              CreateCommon(const long chart,const string name,const int subwin);

   /**
    * @brief EA 模式专属初始化（绑定主窗口，设置最小化尺寸）
    * @param x1 [in] 对话框左上角X坐标
    * @param y1 [in] 对话框左上角Y坐标
    * @param x2 [in] 对话框右下角X坐标
    * @param y2 [in] 对话框右下角Y坐标
    * @return bool - 初始化结果：true=成功（调用父类 Create 完成基础对话框创建），false=失败
    */
   bool              CreateExpert(const int x1,const int y1,const int x2,const int y2);

   /**
    * @brief 指标模式专属初始化（绑定子窗口，自适应宽度）
    * @param x1 [in] 对话框左上角X坐标
    * @param y1 [in] 对话框左上角Y坐标
    * @param x2 [in] 对话框右下角X坐标
    * @param y2 [in] 对话框右下角Y坐标
    * @return bool - 初始化结果：true=成功（子窗口尺寸调整+基础对话框创建），false=失败
    * @note 1. 检查子窗口是否被占用，若占用则删除旧指标；
    *       2. 设置指标短名称，绑定子窗口高度与对话框高度
    */
   bool              CreateIndicator(const int x1,const int y1,const int x2,const int y2);

protected:
   //----------------------------------------------------------------
   // 扩展子控件创建：添加最小化/最大化按钮（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 创建最小化/最大化按钮（绑定 Turn.bmp/Restore.bmp 位图）
    * @return bool - 创建结果：true=成功（按钮位置、状态切换配置完成），false=失败
    */
   virtual bool      CreateButtonMinMax(void);

   //----------------------------------------------------------------
   // 扩展事件回调：处理应用级交互事件（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 关闭按钮点击事件回调（覆盖父类 CDialog::OnClickButtonClose）
    * @details 默认逻辑：调用 Destroy() 销毁对话框并退出程序（而非仅隐藏）
    */
   virtual void      OnClickButtonClose(void);

   /**
    * @brief 最小化/最大化按钮点击事件回调
    * @details 根据按钮当前状态，调用 Minimize() 或 Maximize() 切换窗口尺寸模式
    */
   virtual void      OnClickButtonMinMax(void);

   /**
    * @brief 外部程序关闭事件回调（响应其他实例的 ON_APP_CLOSE 事件）
    * @param lparam [in] 外部程序绑定的子窗口编号
    * @param dparam [in] 预留参数（未使用）
    * @param sparam [in] 外部程序名称
    * @details 调整当前实例的子窗口编号（若外部程序关闭的子窗口编号小于当前），
    *          确保指标子窗口顺序正确
    */
   virtual void      OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam);

   //----------------------------------------------------------------
   // 尺寸调整：实现窗口最小化/最大化逻辑（保护，仅子类可调用）
   //----------------------------------------------------------------
   /**
    * @brief 校准对话框尺寸与位置（适配子窗口，更新客户区大小）
    * @param rect [in] 目标尺寸与位置（CRect 对象）
    * @return bool - 校准结果：true=成功（移动对话框+调整子窗口高度），false=失败
    */
   virtual bool      Rebound(const CRect &rect);

   /**
    * @brief 最小化对话框（切换到紧凑模式）
    * @details 1. 设置 m_minimized 为 true；
    *          2. 调用 Rebound() 应用 m_min_rect 尺寸；
    *          3. 隐藏客户区（ClientAreaVisible(false)），仅显示标题栏和按钮
    */
   virtual void      Minimize(void);

   /**
    * @brief 最大化（恢复）对话框（切换到正常模式）
    * @details 1. 设置 m_minimized 为 false；
    *          2. 调用 Rebound() 应用 m_norm_rect 尺寸；
    *          3. 显示客户区（ClientAreaVisible(true)）
    */
   virtual void      Maximize(void);

   //----------------------------------------------------------------
   // 工具方法：辅助功能（保护，仅子类可调用）
   //----------------------------------------------------------------
   /**
    * @brief 生成实例唯一ID（用于区分同一程序的多个图表实例）
    * @return string - 5位随机数字组成的唯一ID（如 "12345"）
    */
   string            CreateInstanceId(void);

   /**
    * @brief 获取程序名称（EA/指标的名称）
    * @return string - 程序名称（从 m_program_name 读取）
    */
   string            ProgramName(void) const;

   /**
    * @brief 计算子窗口Y轴偏移量（校准鼠标坐标）
    * @details 通过 m_chart.SubwindowY(m_subwin) 获取子窗口顶部相对于图表顶部的偏移，
    *          确保鼠标点击坐标正确映射到对话框局部坐标系
    */
   void              SubwinOff(void);
  };

//+------------------------------------------------------------------+
//| CAppDialog 事件映射：关联扩展子控件事件到处理函数                 |
//+------------------------------------------------------------------+
// EVENT_MAP_BEGIN(CAppDialog)
//    ON_EVENT(ON_CLICK, m_button_minmax, OnClickButtonMinMax)  // 最小化/最大化按钮点击 → 调用 OnClickButtonMinMax
//    ON_EXTERNAL_EVENT(ON_APP_CLOSE, OnAnotherApplicationClose) // 外部程序关闭事件 → 调用 OnAnotherApplicationClose
// EVENT_MAP_END(CDialog)
// //+------------------------------------------------------------------+